#include "unixhead.h"

#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>

#include <iostream>
using namespace std;

static WFFacilities::WaitGroup waitGroup(1);

void sighandler(int signum)
{
    cout << "wait group done\n";
    (void)signum;
    waitGroup.done();
}

struct SeriesContext
{
    string password;
    protocol::HttpResponse * resp;
};

void redisCallback(WFRedisTask * redisTask);

void httpCallback(WFHttpTask * serverTask);

void process(WFHttpTask * serverTask)
{
    cout << "process function is running\n";
    int state = serverTask->get_state();
    int error = serverTask->get_error();
    cout << "state:" << state << endl;
    switch(state){
    case WFT_STATE_SYS_ERROR:
        fprintf(stderr, "system error: %s\n", strerror(error)); break;
    case WFT_STATE_NOREPLY:
        printf("state is WFT_STATE_NOREPLY\n"); break;
    }

    //接下来是要进行回复
    if(state != WFT_STATE_TOREPLY) {
        printf("error occurs!\n");
        return;
    }
    
    //获取uri, 解析请求
    auto req = serverTask->get_req();
    string uri = req->get_request_uri();
    cout << "uri:" << uri << endl;
    //提取用户名和密码
    string namePasswdKV = uri.substr(uri.find("?")+1);
    string nameKV = namePasswdKV.substr(0, namePasswdKV.find("&"));
    string passwordKV = namePasswdKV.substr(namePasswdKV.find("&") + 1);
    string name = nameKV.substr(nameKV.find("=") + 1);
    string password = passwordKV.substr(passwordKV.find("=") + 1);
    cout << "name:" << name << endl
         << "password:" << password << endl;

    //设置共享数据
    auto context = new SeriesContext();
    context->password = password;
    context->resp = serverTask->get_resp();
    series_of(serverTask)->set_context(context);

    //通过Redis任务进行密码的检测
    string url("redis://127.0.0.1:6379");
    auto redisTask = WFTaskFactory::create_redis_task(url, 0, redisCallback);
    auto redisReq = redisTask->get_req();
    redisReq->set_request("HGET", {"student", name});
    //将Redis任务添加到序列中
    series_of(serverTask)->push_back(redisTask);

    //方案一:添加响应的起始行和首部字段
    //方案二:在基本工作对应的回调函数中进行
    serverTask->set_callback(httpCallback);

}

int main()
{
    signal(SIGINT, sighandler);

    WFHttpServer server(process);

    //start的返回值监听成功返回值为0
    if(0 == server.start(8888)) {
        waitGroup.wait();
        server.stop();   
    } else {
        cout << "server start error!\n";
    }

    return 0;
}


void redisCallback(WFRedisTask * redisTask)
{
    cout << "redisTask callback is running\n";
    auto req = redisTask->get_req();
    auto resp = redisTask->get_resp();
    int state = redisTask->get_state();
    int error = redisTask->get_error();
    protocol::RedisValue value;
    switch(state){
    case WFT_STATE_SYS_ERROR:
        fprintf(stderr, "system error: %s\n", strerror(error)); break;
    case WFT_STATE_DNS_ERROR:
        fprintf(stderr, "dns error: %s\n", gai_strerror(error)); break;
    case WFT_STATE_SUCCESS:
        resp->get_result(value);
        if(value.is_error()) {
            fprintf(stderr, "redis error\n");
            state = WFT_STATE_TASK_ERROR;
        }
        break;
    }

    if(state != WFT_STATE_SUCCESS) {
        printf("error occurs\n");
        return;
    }

    //遍历RedisRequest
    string cmd;
    vector<string> params;
    req->get_command(cmd);
    req->get_params(params);
    cout << "redis command: " << cmd << " ";
    for(auto & param : params) {
        cout << param << " ";
    }
    cout << endl;

    //在RedisTask的回调函数中获取共享数据
    SeriesContext * context = 
        static_cast<SeriesContext*>(series_of(redisTask)->get_context());

    //遍历RedisResponse.RedisValue
    if(value.is_string()) {
        cout << "value is a string, value: " 
             << value.string_value() << endl;
        //与从Http请求之中获取的密码进行对比
        if(value.string_value() == context->password) {
            //登录成功, 生成响应
            context->resp->append_output_body("Login Success!");
        } else {
            //登录失败, 生成响应
            context->resp->append_output_body("Login Failed!");
        }
    } else {
        //登录失败, 生成响应
        context->resp->append_output_body("Login Failed!");
    }
}

void httpCallback(WFHttpTask * serverTask)
{
    cout << "serverTask callback is running" << endl;
    auto resp = serverTask->get_resp();   
    //添加起始行和首部字段
    resp->set_http_version("HTTP/1.1");
    resp->set_status_code("200");
    resp->set_reason_phrase("OK");

    resp->add_header_pair("Server", "Workflow Server");
    resp->add_header_pair("Accept", "*/*");
    resp->add_header_pair("Content-Type", "text/plain");

    //释放context对象
    auto context = static_cast<SeriesContext*>(series_of(serverTask)->get_context());
    delete context;
}
